package repo

import (
	"bytes"
	"os"
	"path"
	"text/template"

	"gitee.com/linxing_3/sr-core/yerr"
	"gitee.com/mkwchecking/sr-admin/apps/devtools/conf"
)

func NewClassGen() *ClassGenRepo {
	return &ClassGenRepo{
		tplDir: conf.Config.Devtools.TemplateDir,
	}
}

type ClassGenRepo struct {
	tplRepo

	tplDir string // default (template/devtools)
}

func (r *ClassGenRepo) WithTplDir(tplDir string) *ClassGenRepo {
	r.tplDir = tplDir
	return r
}

func (r *ClassGenRepo) ExecuteBackAcl(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/acl.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteBackApi(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/api.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteBackEntity(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/entity.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteBackHttpClient(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/http_client.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteBackHttpRouter(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/http_router.go.tpl", arg)
}

// http_test
func (r *ClassGenRepo) ExecuteBackHttpTest(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/http_test.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteBackRepo(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/repo.go.tpl", arg)
}
func (r *ClassGenRepo) ExecuteBackService(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "backend/go/service.go.tpl", arg)
}

func (r *ClassGenRepo) ExecuteFrontApi(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "frontend/api.ts.tpl", arg)
}

func (r *ClassGenRepo) ExecuteFrontView(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "frontend/crud.vue.tpl", arg)
}

func (r *ClassGenRepo) ExecuteFrontViewProvider(arg any) (string, error) {
	return r.executeTpl(r.tplDir, "frontend/provider.tsx.tpl", arg)
}

type tplRepo struct {
}

func (r tplRepo) getTpl(name, tplDir string) (*template.Template, error) {
	p := path.Join(tplDir, name)
	if stat, err := os.Stat(p); err != nil {
		return nil, err
	} else if stat.IsDir() {
		return nil, yerr.ErrBizParamInvalid.Errorf("path %s is dir", p)
	}

	_, extName := path.Split(name)
	t := template.New(extName)
	tpl, err := t.ParseFiles(p)
	if err != nil {
		return nil, err
	}
	return tpl, nil
}

func (r tplRepo) executeTpl(tplDir, name string, arg any) (string, error) {
	tpl, err := r.getTpl(name, tplDir)
	if err != nil {
		return "", err
	}

	out := bytes.NewBufferString("")
	err = tpl.Execute(out, arg)
	if err != nil {
		return "", err
	}
	return out.String(), nil
}
